/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.seari.seiec104.client;

import com.seari.seiec104.bean.Iec104Device;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openmuc.j60870.ASdu;
import org.openmuc.j60870.CauseOfTransmission;
import org.openmuc.j60870.ClientConnectionBuilder;
import org.openmuc.j60870.Connection;
import org.openmuc.j60870.ConnectionEventListener;
import org.openmuc.j60870.IeQualifierOfCounterInterrogation;
import org.openmuc.j60870.IeQualifierOfInterrogation;
import org.openmuc.j60870.exception.ConnectionLostException;

/**
 *
 * @author Rainbow
 */
public class IEC104BaseClient
{

    private volatile Connection connection;
    private BaseDataProcessor processor;
    private Iec104Device device;

    public IEC104BaseClient(Iec104Device device)
    {
        this.device = device;
    }

    public void setupClient()
    {
        InetAddress address;
        String ip = device.getIp();
        int port = device.getPort();
        try
        {
            address = InetAddress.getByName(ip);
        } catch (UnknownHostException e)
        {
            System.out.println("Unknown host: " + ip);
            return;
        }
        ClientConnectionBuilder clientConnectionBuilder = new ClientConnectionBuilder(address).setPort(port);

        try
        {
            connection = clientConnectionBuilder.connect();
        } catch (IOException e)
        {
            System.out.println("Unable to connect to remote host: " + ip + ":" + port);
            return;
        }

        Runtime.getRuntime().addShutdownHook(new Thread()
        {
            @Override
            public void run()
            {
                connection.close();
            }
        });

        try
        {
            connection.startDataTransfer(new ClientEventListener(), 5000);
        } catch (TimeoutException e2)
        {
            System.out.println("Starting data transfer timed out. Closing connection.");
            connection.close();
            return;
        } catch (IOException e)
        {
            System.out.println("Connection closed for the following reason: " + e.getMessage());
            return;
        }
        System.out.println("successfully connected");
        if (processor == null)
        {
            System.out.println("processor is null");
        } else
        {
            processor.setReady(true);
        }
    }

    public void sendInterrogation() throws ConnectionLostException
    {
        try
        {
            if (connection != null && (!connection.isSocketClosed()))
            {
                connection.interrogation(device.getStationID(), CauseOfTransmission.ACTIVATION,
                        new IeQualifierOfInterrogation(20));
            } else
            {
                throw new ConnectionLostException();
            }
        } catch (IOException ex)
        {
            Logger.getLogger(IEC104BaseClient.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void sendCounterInterrogation() throws ConnectionLostException
    {
        try
        {
            if (connection != null && (!connection.isSocketClosed()))
            {
                connection.counterInterrogation(device.getStationID(), CauseOfTransmission.ACTIVATION,
                        new IeQualifierOfCounterInterrogation(5, 1));
            } else
            {
                throw new ConnectionLostException();
            }
        } catch (IOException ex)
        {
            Logger.getLogger(IEC104BaseClient.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void resetClient()
    {
        if (connection != null)
        {
            connection.close();
        }
        setupClient();
        try
        {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException ex)
        {
            Logger.getLogger(IEC104BaseClient.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private class ClientEventListener implements ConnectionEventListener
    {

        @Override
        public void newASdu(ASdu aSdu)
        {
            //System.out.println("\nReceived ASDU:\n" + aSdu);
            processor.processData(aSdu);
        }

        @Override
        public void connectionClosed(IOException e)
        {
            System.out.print("Received connection closed signal. Reason: ");
            if (!e.getMessage().isEmpty())
            {
                System.out.println(e.getMessage());
            } else
            {
                System.out.println("unknown");
            }
        }

    }

    public Connection getConnection()
    {
        return connection;
    }

    public void setConnection(Connection connection)
    {
        this.connection = connection;
    }

    public BaseDataProcessor getProcessor()
    {
        return processor;
    }

    public void setProcessor(BaseDataProcessor processor)
    {
        this.processor = processor;
    }

    public Iec104Device getDevice()
    {
        return device;
    }

    public void setDevice(Iec104Device device)
    {
        this.device = device;
    }

}
